/*
 * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package org.jetbrains.dokka.versioning

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.jetbrains.dokka.plugability.*
import org.jetbrains.dokka.renderers.PostAction
import org.jetbrains.dokka.templates.TemplateProcessingStrategy
import org.jetbrains.dokka.templates.TemplatingPlugin
import java.io.File

public class DefaultPreviousDocumentationCopyPostAction(
    private val context: DokkaContext
) : PostAction {
    private val versioningStorage by lazy { context.plugin<VersioningPlugin>().querySingle { versioningStorage } }
    private val processingStrategies: List<TemplateProcessingStrategy> =
        context.plugin<TemplatingPlugin>().query { templateProcessingStrategy }

    private val configuration = configuration<VersioningPlugin, VersioningConfiguration>(context)

    override fun invoke() {
        versioningStorage.createVersionFile()
        versioningStorage.previousVersions.forEach { (_, dirs) -> copyVersion(dirs.src, dirs.dst) }
    }

    private fun copyVersion(versionRoot: File, targetParent: File) {
        targetParent.apply { mkdirs() }
        val olderVersionsDirName =
            configuration?.olderVersionsDirName ?: VersioningConfiguration.defaultOlderVersionsDirName
        val ignoredDirs = when {
            olderVersionsDirName.isBlank() -> versioningStorage.previousVersions.keys
            else -> setOf(olderVersionsDirName)
        }.map { versionRoot.resolve(it).absolutePath }

        runBlocking(Dispatchers.Default) {
            coroutineScope {
                versionRoot.listFiles().orEmpty()
                    .filter { it.absolutePath !in ignoredDirs }
                    .forEach { versionRootContent ->
                        launch {
                            processRecursively(versionRootContent, targetParent)
                        }
                    }
            }
        }
    }

    private fun processRecursively(versionRootContent: File, targetParent: File) {
        if (versionRootContent.isDirectory) {
            val target = targetParent.resolve(versionRootContent.name).also { it.mkdir() }
            versionRootContent.listFiles()?.forEach {
                processRecursively(it, target)
            }
        } else if (versionRootContent.extension == "html") processingStrategies.first {
            it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null)
        } else {
            versionRootContent.copyTo(targetParent.resolve(versionRootContent.name), overwrite = true)
        }
    }
}
